home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / lib / util / lk_lock.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  9.3 KB  |  374 lines

  1. #include "util.h"
  2. #include <sys/stat.h>
  3.  
  4. /*
  5.  *    Standardized file-locking package  (using links)
  6.  *
  7.  *  This version presumes no o/s support of locking, with
  8.  *  link(2) being the only available atomic o/s operation.
  9.  */
  10.  
  11. extern int errno;               /* simulate system error problems */
  12. #ifdef DEBUG
  13. #include "ll_log.h"
  14. extern LLog *logptr;
  15. #endif
  16.  
  17. extern    char *lckdfldir;
  18.  
  19. LOCVAR    int breaktime = 120;   /* amount to sleep after breaking lock */
  20. LOCVAR    char *NIL = "NIL";
  21.  
  22. /* */
  23.  
  24. LOCFUN
  25. lk_lock (fd, file, lockdir, lockfile, maxtime)
  26. int    fd;            /* file to be locked */
  27. char    *file;            /* file to be locked */
  28. char    *lockdir;        /* directory to put parallel file into */
  29. char    *lockfile;        /* file to lock against */
  30. int    maxtime;        /* maybe break lock after it is this old */
  31. {
  32.     int sleepval;
  33.     int retval;
  34.     int tries;
  35.     char lkname[100];           /* full name of locking file */
  36.     char tmpname[100];          /* name of tmp file to link from */
  37.  
  38. #ifdef DEBUG
  39.     ll_log (logptr, LLOGBTR, "lk_lock (%s,%s,%s,%d)", file,
  40.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL, maxtime);
  41. #endif
  42.  
  43.     if (lk_name (lkname, fd, file, lockdir, lockfile) < OK)
  44.     return (NOTOK);
  45.  
  46. #ifdef DEBUG
  47.     ll_log (logptr, LLOGFTR, "lkname '%s'", lkname);
  48. #endif
  49.  
  50.     for (tries = 0; tries < 2; tries++)
  51.     switch (lk_test (file, lkname, maxtime))
  52.     {
  53.         case OK:                /* lock exists & is ok */
  54. #ifdef DEBUG
  55.         ll_log (logptr, LLOGFTR, "already locked & ok");
  56. #endif
  57.         errno = ETXTBSY;
  58.         return (NOTOK);
  59.  
  60.         case NOTOK:             /* lock exists and is old */
  61. #ifdef DEBUG
  62.         ll_log (logptr, LLOGFTR, "old lock");
  63. #endif
  64.         if (lk_unlock (fd, file, lockdir, lockfile) == NOTOK)
  65.             return (NOTOK); /* hmmmmmm */
  66.  
  67. /*
  68.  *  the amount of time to sleep is at least breaktime.
  69.  *  the random number generation is used to try to separate
  70.  *  two processes that may be close to syncrony in checking the lock.
  71.  */
  72.         srand (getpid ());
  73.         sleepval = breaktime + (rand ()%100);
  74. #ifdef DEBUG
  75.         ll_log (logptr, LLOGFTR, "sleeping (%d)", sleepval);
  76. #endif
  77.         sleep (sleepval);
  78.         continue;
  79.  
  80.         default:
  81.         goto lockit;
  82.     }
  83.  
  84. /* below here, try to lock the guy */
  85.  
  86. lockit:
  87.     getfpath (",tmp.XXXXXX", lockdir ? lockdir : lckdfldir, tmpname);
  88.     mktemp (tmpname);           /* have to have something to link from */
  89.  
  90.     if (close (creat (tmpname, 0666)) < OK)
  91.     {
  92. #ifdef DEBUG
  93.     ll_err (logptr, LLOGFTR, "problem w/lock base file '%s'", tmpname);
  94. #endif
  95.     (void) unlink (tmpname);
  96.     return (NOTOK);
  97.     }
  98.  
  99.     retval = link (tmpname, lkname);
  100.  
  101. #ifdef DEBUG
  102.     if (retval < 0)
  103.     ll_err (logptr, LLOGFTR,
  104.             "problem linking '%s' to '%s'", tmpname, lkname);
  105.     else
  106.     ll_log (logptr, LLOGFTR,
  107.             "linked '%s' to '%s'", tmpname, lkname);
  108. #endif
  109.  
  110.     (void) unlink (tmpname);
  111.  
  112.     return (retval);
  113. }
  114. /* */
  115.  
  116. LOCFUN
  117. lk_unlock (fd, file, lockdir, lockfile)
  118. int    fd;        /* file to be locked */
  119. char    *file;        /* file to be locked */
  120. char    *lockdir;    /* directory to put parallel file into */
  121. char    *lockfile;    /* file to lock against */
  122. {
  123.     int retval;
  124.     char lkname[100];           /* full name of locking file */
  125.  
  126. #ifdef DEBUG
  127.     ll_log (logptr, LLOGBTR, "lk_unlock (%s,%s,%s)", file,
  128.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  129. #endif
  130.  
  131.     if (lk_name (lkname, fd, file, lockdir, lockfile) < OK)
  132.     return (NOTOK);
  133.  
  134.     retval = unlink (lkname);
  135.  
  136. #ifdef DEBUG
  137.     if (retval < 0)
  138.     ll_err (logptr, LLOGFTR, "problem unlinking '%s'", lkname);
  139. #endif
  140.  
  141.     return (retval);
  142. }
  143.  
  144. /* */
  145.  
  146. LOCFUN
  147. lk_name (lkname, fd, file, lockdir, lockfile)
  148. char    *lkname;        /* put full name of file to use as lock */
  149. int    fd;            /* file to be locked */
  150. char    *file;            /* resource to be locked */
  151. char    *lockdir;        /* dir containing locking file, if any */
  152. char    *lockfile;        /* file to use ask lock */
  153. {
  154.     struct stat statbuf;
  155.  
  156. #ifdef DEBUG
  157.     ll_log (logptr, LLOGBTR, "lk_name (%s,%s,%s)", file,
  158.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  159. #endif
  160.  
  161.     if (lockdir == (char *) 0)
  162.     lockdir = lckdfldir;
  163.  
  164.     if (lockfile && *lockfile )
  165.     getfpath (lockfile, lockdir, lkname);
  166.     else {                      /* make out own file name */
  167.     if (fstat (fd, &statbuf) < OK) /* no way to create a fixed name */
  168.         return (NOTOK);
  169.     sprintf (lkname, "%s/LCK%05d.%05d",
  170.             lockdir, statbuf.st_dev, statbuf.st_ino);
  171.     }
  172.  
  173.     return (OK);
  174. }
  175. /* */
  176.  
  177. LOCFUN
  178. lk_test (file, lkfile, maxtime)
  179. char    *file;
  180. char    *lkfile;
  181. int    maxtime;
  182. {
  183.     time_t curtime;
  184.     struct stat statbuf;
  185.  
  186.     time (&curtime);
  187.  
  188.     if (stat (lkfile, &statbuf) < OK)
  189.     {
  190. #ifdef DEBUG
  191.     ll_err (logptr, LLOGBTR, "lk_test couldn't stat lockfile '%s'", lkfile);
  192. #endif
  193.     return (DONE);          /* assume that it does not exist */
  194.     }
  195.     if (maxtime <= 0)
  196.     return (OK);            /* no time limit */
  197.  
  198. #ifdef DEBUG
  199.     ll_log (logptr, LLOGBTR, "lockfile (%ld:%ld) minutes",
  200.         (((curtime - statbuf.st_mtime)+59L)/60L), (long) (maxtime));
  201. #endif
  202.     if ((((curtime - statbuf.st_mtime)+59L)/60L) > (long) (maxtime))
  203.     {                           /* well, the lock is too old */
  204.     if (file != (char *) 0) /* is the resource inactive, also? */
  205.         if (stat (file, &statbuf) >= OK)
  206.         {
  207. #ifdef DEBUG
  208.         ll_log (logptr, LLOGBTR, "resource access (%ld:%ld) minutes",
  209.             (((curtime - statbuf.st_mtime)+59L)/60L), (long) (maxtime));
  210. #endif
  211.         if ((((curtime - statbuf.st_atime)+59L)/60L) <= (long) (maxtime))
  212.             return (OK); /* let them go */
  213.         }
  214.     return (NOTOK);
  215.     }
  216.  
  217.     return (OK);        /* lock still has time */
  218. }
  219. /* */
  220.  
  221. LOCFUN
  222. lk_creat (file, mode, lockdir, lockfile, maxtime)
  223. char    *file;            /* file to be created */
  224. int    mode;            /* creation mode */
  225. char    *lockdir;        /* directory to put parallel file into */
  226. char    *lockfile;        /* file to lock against */
  227. int    maxtime;        /* maybe break lock after it is this old */
  228. {
  229.     register fd;
  230.     register char *p;
  231.     char tempname[100];
  232.     extern char *rindex ();
  233.  
  234. #ifdef DEBUG
  235.     ll_log (logptr, LLOGBTR, "lk_creat (%s,0%o,%s,%s)", file, mode,
  236.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  237. #endif
  238.  
  239. retry:
  240.     if ((fd = lk_open (file, 1, lockdir, lockfile, maxtime)) >= 0) {
  241.     close (creat (file, mode));
  242.     return (fd);
  243.     }
  244.     if (errno != ENOENT)
  245.     return (NOTOK);
  246.     /* file didn't exist */
  247.     if (p = rindex (file, '/')) {
  248.     *p = '\0';
  249.     (void) strcpy (tempname, file);
  250.     *p = '/';
  251.     (void) strcat (tempname, "/");
  252.     } else
  253.     tempname[0] = '\0';
  254.     (void) strcat (tempname, ",tmpXXXXXX");
  255.     fd = creat (tempname, mode);
  256.     if (fd < 0)
  257.     return (NOTOK);
  258.     if (lk_lock (fd, tempname, lockdir, lockfile, maxtime) < 0) {
  259.     unlink (tempname);
  260.     close (fd);
  261.     return (NOTOK);
  262.     }
  263.     if (link (tempname, file) < 0) {
  264.     lk_unlock (fd, tempname, lockdir, lockfile);
  265.     close (fd);
  266.     unlink (tempname);
  267.     if (errno == EEXIST)
  268.         goto retry;
  269.     return (NOTOK);
  270.     }
  271.     unlink (tempname);
  272.     return (fd);
  273. }
  274.  
  275. lk_open (file, access, lockdir, lockfile, maxtime)
  276. char    *file;            /* file to be locked */
  277. int    access;            /* read-write permissions */
  278. char    *lockdir;        /* directory to put parallel file into */
  279. char    *lockfile;        /* file to lock against */
  280. int    maxtime;        /* maybe break lock after it is this old */
  281. {
  282.     register fd;
  283.  
  284. #ifdef DEBUG
  285.     ll_log (logptr, LLOGBTR, "lk_open (%s,%d,%s,%s,%d)", file, access,
  286.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL, maxtime);
  287. #endif
  288.  
  289.     if ((fd = open (file, access)) < 0) {
  290. #ifdef DEBUG
  291.         ll_err (logptr, LLOGBTR, "open not ok (errno %d)", errno);
  292. #endif
  293.     return (NOTOK);
  294.     }
  295.     if (lk_lock (fd, file, lockdir, lockfile, maxtime) < 0) {
  296. #ifdef DEBUG
  297.         ll_err (logptr, LLOGBTR, "open lock not ok");
  298. #endif
  299.     close (fd);
  300.     return (NOTOK);
  301.     }
  302.     return (fd);
  303. }
  304.  
  305. lk_close (fd, file, lockdir, lockfile)
  306. int fd;
  307. char    *file;            /* file to be locked */
  308. char    *lockdir;        /* directory to put parallel file into */
  309. char    *lockfile;        /* file to lock against */
  310. {
  311. #ifdef DEBUG
  312.     ll_log (logptr, LLOGBTR, "lk_close (%d,%s,%s,%s)", fd, file,
  313.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  314. #endif
  315.     if (fd < 0)
  316.     return (OK);
  317.     lk_unlock (fd, file, lockdir, lockfile);
  318.     return (close (fd));
  319. }
  320.  
  321. FILE *
  322. lk_fopen (file, mode, lockdir, lockfile, maxtime)
  323. char    *file;            /* file to be locked */
  324. char    *mode;            /* read-write permissions */
  325. char    *lockdir;        /* directory to put parallel file into */
  326. char    *lockfile;        /* file to lock against */
  327. int    maxtime;        /* maybe break lock after it is this old */
  328. {
  329.     register fd;
  330.     register FILE *f;
  331.  
  332. #ifdef DEBUG
  333.     ll_log (logptr, LLOGBTR, "lk_fopen (%s,%s,%s,%s)", file, mode,
  334.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  335. #endif
  336.  
  337.     if ((fd = open (file, 0)) < 0 && (fd = open (file, 1)) < 0) {
  338.     if (*mode != 'a' && *mode != 'w')
  339.         return (NULL);
  340.     fd = lk_creat (file, 0666, lockdir, lockfile, maxtime);
  341.     if (fd < 0)
  342.         return (NULL);
  343.     } else
  344.     if (lk_lock (fd, file, lockdir, lockfile, maxtime) < 0) {
  345.         close (fd);
  346.         return (NULL);
  347.     }
  348.     /* file is opened and locked; now fopen it */
  349.     if ((f = fopen (file, mode)) == 0) {
  350.     lk_unlock (fd, file, lockfile, lockdir);
  351.     close (fd);
  352.     return (NULL);
  353.     }
  354.     close (fd);
  355.     return (f);
  356. }
  357.  
  358. lk_fclose (fp, file, lockdir, lockfile)
  359. FILE    *fp;
  360. char    *file;            /* file to be locked */
  361. char    *lockdir;        /* directory to put parallel file into */
  362. char    *lockfile;        /* file to lock against */
  363. {
  364. #ifdef DEBUG
  365.     ll_log (logptr, LLOGBTR, "lk_fclose (%s,%s,%s)", file,
  366.         lockdir ? lockdir : NIL, lockfile ? lockfile : NIL);
  367. #endif
  368.     if (fp == NULL)
  369.     return (EOF);
  370.     fflush (fp);
  371.     lk_unlock (fileno (fp), file, lockdir, lockfile);
  372.     return (fclose (fp));
  373. }
  374.